package operation;

import basic.JodisDb;
import basic.JodisObject;
import utils.StringUtils;
import utils.TimeUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class KeyOperation extends AbstractOperation{
    public KeyOperation(JodisDb jodisDb){super(jodisDb);}

    public JodisObject getJodisObject(String key){
        /**
         * 这里需要去判断是否过期，过期则返回NULL
         * **/
        long current = TimeUtil.getSystemTime();
        long exipreAt = this.jodisDb.getExpireByKey(key);
        if(exipreAt == -1){
            //未设置过期时间
            return this.jodisDb.get(key);
        }
        //未过期
        if(exipreAt >= current){
            return this.jodisDb.get(key);
        }

        //惰性删除，删除键空间和过期键空间对应的key
        if (this.jodisDb.containsKey(key)) {
            this.jodisDb.remove(key);
            if(this.jodisDb.containsExpireKey(key)){
                this.jodisDb.removeExpire(key);
            }
        }

        return null;
    }


    public int size() {
        return jodisDb.size();
    }

    /**
     * Redis command: TYPE
     * @param key
     * @return
     */
    public String type(String key) {
        if (!exists(key)) {
            return null;
        }
        return getJodisObject(key).type();
    }

    /**
     * 如果集合为空直接删除
     * Redis command: DEL
     * @param key
     * @return
     */
    public int delete(String key) {
        if (this.jodisDb.containsKey(key)) {
            this.jodisDb.remove(key);
            if(this.jodisDb.containsExpireKey(key)){
                this.jodisDb.removeExpire(key);
            }
            return 1;
        }
        return 0;
    }


    /**
     * Redis command: EXISTS
     * @param key
     * @return
     */
    public boolean exists(String key) {
        return this.jodisDb.containsKey(key);
    }


    /**
     * @param key 秒为基本单位
     * @return
     */
    public int expire(String key, long timestamp) {
        long current = TimeUtil.getSystemTime() ;
        //此处硬编码了，这里的时间戳是13位，以毫秒计数
        timestamp = current + timestamp*1000;
        return this.jodisDb.expire(key,timestamp);
    }

    /**
     * todo TTL
     * @param key
     * @return
     */
    public int expireAt(String key, long timestamp, TimeUnit unit) {
        return 0;
    }

    /**
     * Redis command: KEYS
     * @param pattern
     * @return
     */
    public List<String> keys(String pattern) {
        if (StringUtils.equals(StringUtils.STAR, pattern)) {
            return new ArrayList<>(this.jodisDb.keySet());
        }

        return this.jodisDb.keySet()
                .stream()
                .filter(key -> key.startsWith(pattern))
                .collect(Collectors.toList());
    }

    /**
     * @param key
     * @param unit
     * @return -1表示未设置过期时间  0表示已经过期  >0表示剩余存活的时间
     */
    public long ttl(String key, long timestamp, TimeUnit unit) {
        //getJodisObject里面要判断key是否过期
        long expireAt = this.jodisDb.getExpireByKey(key);
        long current = TimeUtil.getSystemTime();
        if(expireAt == -1) return -1;
        if(expireAt < current) return 0;
        return expireAt-current;
    }

    /**
     * Redis command: RENAME
     * @param key
     * @param newKey
     */
    public boolean rename(String key, String newKey) {
        if (StringUtils.equals(key, newKey) || !exists(key)) {
            return false;
        }
        JodisObject value = getJodisObject(key);
        delete(key);
        this.jodisDb.put(newKey, value);
        return true;
    }

    /**
     * Redis command: RENAMENX
     * @param key
     * @param newKey
     */
    public boolean renameIfNotExist(String key, String newKey) {
        if (exists(newKey)) {
            return false;
        }
        return rename(key, newKey);
    }

    /**
     * Redis command: RANDOMKEY
     * @return
     */
    public String randomKey(){
        if (size() > 0) {
            return this.jodisDb.keySet().iterator().next();
        }
        return null;
    }
}
